/**
 * @file flash_main.c
 * @brief 
 * @author  ()
 * @version 1.0
 * @date 2024-09-13
 * 
 * @copyright Copyright (C) 2019 Queclink Wireless Solutions (ShenZhen) Co., Ltd. All Rights Reserved.
 * 
 * @par 修改日志:
 * <table>
 * <tr><th>Date       <th>Version <th>Author  <th>Description
 * <tr><td>2024-09-13 <td>1.0     <td>     <td>内容
 * </table>
 */

#ifdef __cplusplus
    extern "C"{
#endif

#define LOG_TAG "PARM"
#include "easylog/elog.h"

#include "bsp_eflash.h"

#include "aadl/flash.h"    
#include "aadl/public.h"
#include "flash/flash_main.h"

#include "protocol_params/protocol_params.h"

#include "misc/task_misc.h"
#include "service/include/swei_config.h"


/******************************************************************************/
const struct flash_zone appflash_table[] = {
    /*  直接读写区 */
    {   
    .type                   =   FZONE_DIRECT,                 /*FOTA标志 -------*/
    .zone_id                =   FILE_OTA_FLAG_ID,
    .name                   =   "FILE_OTA_FLAG",
    .direct.total_size      =   FILE_OTA_FLAG_SIZE,
    }, 
   /*文件区域 ---------------------------------------------------------------*/
    {   
    .type                   =   FZONE_FILE,
    .zone_id                =   FILE_OTA_ID,
    .name                   =   "FILE_OTA",
    .file.total_size        =   FILE_OTA_SIZE,
    },

    {
    .type                   =   FZONE_FREQUENCY,
    .zone_id                =   FREQ_CALIB_COEFF_ID,
    .name                   =   "CALIB_COEFF",
    #warning "Eliminate this warning by define a real snsr_calib_coeff struct"
    .frequency.data_size    =   20, //sizeof(struct snsr_calib_coeff),
    .frequency.total_size   =   K8_SIZE,
    },
    
    //upc下载文件
	{   
    .type                   =   FZONE_FILE,
    .zone_id                =   FILE_CONFIG_ID,
    .name                   =   "FILE_CONFIG",
    .file.total_size        =   FILE_NEW_CONFIG_SIZE,
    },
    
     //l3 lib模式库文件
    {   
    .type                   =   FZONE_FILE,
    .zone_id                =   FILE_L3_LIB_ID,
    .name                   =   "L3_LIB",
    .file.total_size        =   FILE_L3_LIB_SIZE,
    },
    
    /*配置参数区 -------------------------------------------------------------*/
    {   
    .type                   =   FZONE_FATAL,
    .zone_id                =   FATAL_PARA_ID,
    .name                   =   "FATAL_PARA",
    .fatal.data             =   config_params_table,
    .fatal.count            =   sizeof(config_params_table) / sizeof(struct flash_data),
    }, 

    {
    .type                   =   FZONE_FATAL,
    .zone_id                =   FATAL_PARA_ID2,
    .name                   =   "FATAL_PARA2",
    .fatal.data             =   config_params_table,
    .fatal.count            =   sizeof(config_params_table) / sizeof(struct flash_data),
    },

  
    /*频繁写区域 -------------------------------------------------------------*/
#if 0
    {   
    .type                   =   FZONE_FREQUENCY,
    .zone_id                =   FREQ_SREIAL_NUM_ID,
    .name                   =   "SERIAL_NUM",
    .frequency.data_size    =   2,
    .frequency.total_size   =   FREQ_SERIAL_NUM_TOTAL_SIZE,
    },
 
    {   
    .type                   =   FZONE_FREQUENCY,
    .zone_id                =   FREQ_MILEAGE_ID,
    .name                   =   "MILEAGE_FLAG",
    .frequency.data_size    =   sizeof(double),
    .frequency.total_size   =   FREQ_MILEAGE_SIZE,
    },
#endif

    {
    .type                   =   FZONE_FILE,
    .zone_id                =   FILE_CA_FILE_ID,
    .name                   =   "CA_FILE",
    .file.total_size        =   SSL_FILE_SIZE,
    },


    {
    .type                   =   FZONE_FREQUENCY,
    .zone_id                =   FREQ_MISC_DATA_ID,
    .name                   =   "MISC_DATA",
    .frequency.data_size    =   sizeof(misc_save_t),
    .frequency.total_size   =   FREQ_MISC_DATA_SIZE,
    },


    /*循环队列区域 -----------------------------------------------------------*/
#if  0
    {   
    .type                   =   FZONE_CIRCULAR,
    .zone_id                =   QUEUE_EBUF_ID,
    .name                   =   "CIR_EBUF",
    .circular.total_size    =   QUEUE_EBUF_SIZE,
    },     

    {   
    .type                   =   FZONE_CIRCULAR,
    .zone_id                =   QUEUE_HBUF_ID,
    .name                   =   "CIR_HBUF",
    .circular.total_size    =   QUEUE_HBUF_SIZE,
    },  

    {   
    .type                   =   FZONE_CIRCULAR,
    .zone_id                =   QUEUE_SMS_BUF_ID,
    .name                   =   "CIR_BUF_DIAGNOST",
    .circular.total_size    =   QUEUE_SMS_BUF_SIZE,
    },
#endif
    {   
    .type                   =   FZONE_CIRCULAR,
    .zone_id                =   QUEUE_RECORD_ID,
    .name                   =   "CIR_REC",
    .circular.total_size    =   QUEUE_RECORD_SIZE,
    }, 
};


static int32_t flash_enable(void)
{
    return bsp_eflash_enable();
}

static int32_t flash_disable(void)
{
    return bsp_eflash_disable();
}

static inline ssize_t flash_spi_write(const unsigned char *buf, size_t len)
{
	return bsp_eflash_write(buf, len);
}

static inline ssize_t flash_spi_read(unsigned char *buf, size_t len)
{
    return bsp_eflash_read(buf, len);        
}

#if 0
static void show_flash_capacity(void)
{
    flash_id_t Flash_IDdata;
    unsigned char buf[1]={CMD_READ_ID};
    unsigned char buf_r[4]={0};
    flash_enable();
    flash_spi_write(buf,1);
    flash_spi_read(buf_r,3);
    Flash_IDdata.flash_manufacture  = buf_r[0];
    Flash_IDdata.flash_type         = buf_r[1];
    Flash_IDdata.flash_capacity     = buf_r[2];  
    flash_disable();
    flash_debug(LOG_INFO"spiFlash: manufacture:0x%X,type:0x%X,capacity:0x%X\r\n",
            Flash_IDdata.flash_manufacture,
            Flash_IDdata.flash_type,
            Flash_IDdata.flash_capacity);
    if(Flash_IDdata.flash_capacity > 19)
        flash_debug(LOG_INFO"spiFlash size: %dMBytes\r\n", 1 << (Flash_IDdata.flash_capacity -20));
    else
        flash_debug(LOG_INFO"spiFlash size: %dKBytes\r\n", 1 << (Flash_IDdata.flash_capacity -10));
}
#endif
/*flash 初始化*/
int32_t flash_main_init(void){

    /* 初始化SPI */
    bsp_eflash_init();

	static const struct aadl_ops user_aadl_ops = {
	  .debug				= NULL, //printf,
	  //.watchdog_feed		= NULL, //watchdog_feed,
	  .get_ms_since_boot	= NULL, //get_ms_since_boot,
	  .abdicate_resource	= NULL,
	};

    aadl_initialize(&user_aadl_ops);

     /*flash  控制总线定义 --------------------------------------------------------*/
    struct flash_adapter spi_flash_adapter = {
        .enable  = flash_enable,
        .disable = flash_disable,
        .write   = flash_spi_write,
        .read    = flash_spi_read,
        .events_handler = NULL
    };
    uint32_t flashzones = sizeof(appflash_table)/sizeof(struct flash_zone);
    int32_t ret;

    aad_flash_initialize(&spi_flash_adapter);

    ret = aad_flash_format(appflash_table,flashzones,AADL_FORCE,0);
    if (ret < 0) {
        uint32_t i = 0;
        for (i = 0; i < 1000; i++) {
            log_i("aad_flash_format return:%d.\r\n", ret);
        }
        ret = aad_flash_format_fully(appflash_table, flashzones, 0, 0);
    }

    return 0;
}

void load_param_from_flash(void)
{
    /* 从FLASH读取RTC参数 */
	misc_flash_data_init();

    /*读取设备配置信息 */
    swei_config_init();
}

void flash_task_entry (void)
{}

/***************************************************
* write the data into the specific flash direct area.
* @params: id - specific params id.
*                buf - data buffer that would be write in.
*                num - buffer size.
* @retval: negative value - fail, else values - success.
****************************************************/
#pragma optimize=none
int32_t direct_retain_write(direct_id_e id, void *buf, int32_t num)
{
    int32_t retval = 0;

    if ((NULL == buf) ||(num <= 0)) {
        return -EINVAL;
    }
    switch (id) {
    case DRET_ID_OTA://offset 0, size 512 Bytes.
        if (num <= 512) {
            retval = aad_flash_direct_write(DIRECT_RETAIN_ID, 0, buf, num, AADL_KEEP_OUTSIDE, AADL_NO_TIMEOUT);
        } else {
            retval = -EPERM;
        }
        break;
    case DRET_ID_PIN://offset 512, size 32 Bytes.
        if (num <= 32) {
            retval = aad_flash_direct_write(DIRECT_RETAIN_ID, 512, buf, num, AADL_KEEP_OUTSIDE, AADL_NO_TIMEOUT);
        } else {
            retval = -EPERM;
        }
        break;
    case DRET_ID_TEST://offset 544, size 3552
        if (num <= 3552) {
            retval = aad_flash_direct_write(DIRECT_RETAIN_ID, 544, buf, num, AADL_KEEP_OUTSIDE, AADL_NO_TIMEOUT);
        } else {
            retval = -EPERM;
        }
        break;
    default:
        retval = -EINVAL;
        break;
    }
    return retval;
}

/***************************************************
* read the data from the specific flash direct area.
* @params: id - specific params id.
*                buf - the buffer that used to get data.
*                num - buffer size.
* @retval: negative value/zero - fail,
*              positive values - success(readed data count.).
****************************************************/
#pragma optimize=none
int32_t direct_retain_read(direct_id_e id, void *buf, int32_t num)
{
    int32_t retval = 0;
    int32_t rd_num = 0;

    if ((NULL == buf) ||(num <= 0)) {
        return -EINVAL;
    }
    switch (id) {
    case DRET_ID_OTA://offset 0, size 512 Bytes.
        if (num > 512) {
            rd_num = 512;
        } else {
            rd_num = num;
        }
        if (rd_num == aad_flash_direct_read(DIRECT_RETAIN_ID, 0, buf, rd_num)) {
            retval = rd_num;
        } else {
            retval = -EPERM;
        }
        break;
    case DRET_ID_PIN://offset 512, size 32 Bytes.
        if (num > 32) {
            rd_num = 32;
        } else {
            rd_num = num;
        }
        if (rd_num == aad_flash_direct_read(DIRECT_RETAIN_ID, 512, buf, rd_num)) {
            retval = rd_num;
        } else {
            retval = -EPERM;
        }
        break;
    case DRET_ID_TEST://offset 544, size 3552
        if (num > 3552) {
            rd_num = 3552;
        } else {
            rd_num = num;
        }
        if (rd_num == aad_flash_direct_read(DIRECT_RETAIN_ID, 544, buf, rd_num)) {
           retval = rd_num;
        } else {
            retval = -EPERM;
        }
        break;
    default:
        retval = -EINVAL;
        break;
    }
    return retval;
}

/******** >>Please add  above this line <<************/
#ifdef __cplusplus
    }
#endif

/** END FO FILE **/

